#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

//1.pending位图，什么时候从1->0 执行信号捕捉方法之前 先清零，再调用

void PrintPending()
{
    sigset_t set;
    sigpending(&set);

    for(int signo=1;signo<=31;signo++)
    {
        if(sigismember(&set,signo)) cout<<"1";
        else cout<<"0";
    }
    cout<<"\n";
}

void handler(int signo)
{
    PrintPending();
    cout<<"catch a signal, signal number: "<<signo<<endl;
}

int main()
{
    struct sigaction act,oact;
    memset(&act,0,sizeof(act));
    memset(&oact,0,sizeof(oact));

    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask,1);
    sigaddset(&act.sa_mask,3);
    sigaddset(&act.sa_mask,4);
    act.sa_handler=handler;
    sigaction(2,&act,&oact);

    while(true)
    {
        cout<<"I am a process: "<<getpid()<<endl;
        sleep(1);
    }

    return 0;
}


#if 0
void PrintPending(sigset_t &pending)
{
    for(int signo=31;signo>=1;signo--)
    {
        if(sigismember(&pending,signo))
        {
            cout<<"1";
        }
        else 
        {
            cout<<"0";
        }
    }
    cout<<endl;
}

void handler(int signo)
{
    cout<<"catch a signo: "<<signo<<endl;
}

int main()
{
    /*
    //0.对2号信号自定义捕捉
    signal(2,handler);

    //1.1先对2号信号进行屏蔽，准备工作
    sigset_t bset,oset; //用户栈上的数据，属于用户区
    sigemptyset(&bset);
    sigemptyset(&oset);
    sigaddset(&bset,2);  //这里还没有屏蔽好2号信号
    
    //1.2调用系统调用，屏蔽信号设置进内核
    sigprocmask(SIG_SETMASK,&bset,&oset);

    //2.重复打印当前进程的pending 000000000000000000000000
    sigset_t pending;
    int cnt=0;

    while(true)
    {
        //2.1获取
        int n=sigpending(&pending);
        if(n<0) continue;
        
        //2.2打印
        PrintPending(pending);
        sleep(1);
        
        //2.3解除阻塞
        cnt++;
        if(cnt==10)
        {
            cout<<"unlock 2 signo"<<endl;
            sigprocmask(SIG_SETMASK,&oset,nullptr);
        }
    }
    */

    //3.发送2号 000000000000000000000010

    //4.如果我将所有的信号进行屏蔽，信号就不会被处理吗？不会 9和19不会被屏蔽
    sigset_t bset,oset;
    sigemptyset(&bset);
    sigemptyset(&oset);
    for(int i=1;i<=31;i++)
    {
        sigaddset(&bset,i);
    }
    sigprocmask(SIG_SETMASK,&bset,&oset);

    while(true)
    {
        cout<<"proc is running"<<endl;
        sleep(1);
    }

    return 0;
}
#endif

#if 0
int main()
{
    pid_t id=fork();
    if(id==0)
    {
        //child
        int cnt=10;
        while(cnt)
        {
            cout<<"I am a child process, pid: "<<getpid()<<" cnt: "<<cnt<<endl;
            sleep(1);
            cnt--;
        }

        exit(0);
    }

    //father
    int status=0;
    pid_t rid=waitpid(id,&status,0);
    if(rid==id)
    {
        cout<<"child quit info, rid: "<<rid<<" exit code: "<<((status>>8)&0xFF)\
            <<" exit signal: "<<(status&0x7F)<<" core dump: "<<((status>>7&1))<<endl;
    }

    return 0;
}
#endif 


#if 0
//闹钟
void work()
{
    cout<<"print log..."<<endl;
}

void handler(int signo)
{
    work();
    int n=alarm(5);
    cout<<"剩余时间："<<n<<endl;
}

int main()
{
    signal(SIGALRM,handler);
    int n=alarm(5);

    while(1)
    {
        cout<<"proc is running... "<<endl;
        sleep(1);
    }

    return 0;
}
#endif 

#if 0
//为什么信号会一直触发
void handler(int signo)
{
    cout<<"get a sig, number: "<<signo<<endl;
    exit(1);
}

int main()
{
    //signal(SIGFPE,handler); //信号捕捉
    cout<<"div before"<<endl;
    
    signal(11,handler);
    cout<<"point error before"<<endl;

    sleep(3);
    
    //段错误，直接返回退出11号信号
    int *p=nullptr;
    *p=100; //野指针
    
    //int a=10;
    //a/=0; //异常
    cout<<"div after"<<endl;
    sleep(1);
    return 0;
}
#endif

#if 0
void Usage(string proc)
{
    cout<<"Usage:\n\t"<<proc<<" signum pid\n\n";
}

int main(int argc,char *argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    int signum=stoi(argv[1]);
    pid_t pid=stoi(argv[2]);

    int n=kill(pid,signum);
    if(n==-1)
    {
        perror("kill");
        exit(2)
    }

    return 0;
}
#endif 

#if 0
//int：收到了哪一个信号
void myhandler(int signo)
{
    cout<<"Get a signal: "<<signo<<endl;
}

int main()
{
    //修改2号信号对进程的处理动作
    //signal(SIGINT,myhandler); 
    //signal(3,myhandler); 

    for(int i=1;i<=31;i++)
    {
        signal(i,myhandler);
    }

    //信号的产生和我们自己产生的代码的运行时间是异步的
    while(true)
    {
        sleep(1);
        cout<<"I am process"<<endl;
    }
    return 0;
}
#endif 